#ifndef _HTTP_H
#define _HTTP_H

#include "sgl_types.h"
#include "socket.h"

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

/**
  \defgroup http HTTP Management

  @section http_intro Introduction

  Http Module is based on socket module, so socket module should be initialized before http initialize.
  This module is a simple module just help you in two case: format http request header; parse the response header;
  The http method "HEAD" is not supported by default for extra resource, please define HTTP_HEAD_METHOD_ENABLE
  to enable this method as needed.

  @section http_session Typical Session
  
  To work with Http Module:
  - Create your Http events handler.
  - Call Http_Open to create  the http socket with your events handler.
  - Call Http_Get/Http_Head/Http_Post to send Http request.
  
  \code
  	//Your http socket events handler
	DWORD UserHttpEventsHandler(PSOCKET socket, DWORD evt, PSOCKEVTDATA data)
	{
		switch(evt)
		{
		case HTTPEVT_CONNECTED:
			//connect successfully
			//Http_Get(socket, "http://www.xxx.com", 0, 0); //could put request here
			break;

		case HTTPEVT_RESPONSE_HEADER:
			//receive the http response header
			break;

		case HTTPEVT_RESPONSE_DATA:
			//receive the http response data
			break;

		case HTTPEVT_RESPONSE_END:
			//a response finished, if just one request call close here and return 1
			break;

		case HTTPEVT_CONNECTFAILED:
		case HTTPEVT_ERROR:
			//error handling
			break;

		case HTTPEVT_CLOSED:
			//finished use
			break;
		}

		return 0;
	}

	//Your Code
	socket = Http_Open(ip, port, UserHttpEventsHandler);
	if(socket)
	{
		//This is supported, before the http connected the request be cached.
		Http_Get(socket, "http://www.xxx.com", 0, 0);
	}
  \endcode
  
  @ingroup network
  @{
 */

/**
 * \brief default http port
 */
#ifndef HTTP_PORT
#define HTTP_PORT		80
#endif

/**
 * \brief default wap proxy
 */
#ifndef WAPPROXYIP
#define WAPPROXYIP		"10.0.0.172"
#endif

/**
 * \brief default wap proxy port
 */
#ifndef WAPPROXYPORT
#define WAPPROXYPORT	HTTP_PORT
#endif

/**
 * \brief max http header size in bytes
 */
#ifndef HTTP_HEADER_SIZE
#define HTTP_HEADER_SIZE				1024
#endif

#ifndef HTTP_MSG_SIZE
#define HTTP_MSG_SIZE				2048
#endif

/**
 * \brief max field value length in response header
 */
#ifndef HTTP_FIELDVALUE_SIZE
#define HTTP_FIELDVALUE_SIZE			128
#endif

/**
 * \brief pre-defined http fields and values
 */
#define HTTP_HEADER_FORMAT "%s %s HTTP/1.1\r\n"
#define HTTP_FIELD_HOST	"Host"
#define HTTP_FIELD_XHOST 	"X-Online-Host"
#define HTTP_FIELD_RANGE	"Range"
#define HTTP_FIELD_CONTENTLENGTH	"Content-Length"
#define HTTP_FIELD_UA	"User-Agent"
#define HTTP_VALUE_UA	"Nokia6681/2.0 (3.10.6) SymbianOS/8.0 Series60/2.6 Profile/MIDP-2.0 Configuration/CLDC-1.1"
#define HTTP_FIELD_ACCEPT	"Accept"
#define HTTP_VALUE_ACCEPT	"*/*"
#define HTTP_FIELD_ACCEPT_LANGUAGE 	"Accept-Language"
#define HTTP_VALUE_ACCEPT_LANGUAGE 	"zh-cn"
#define HTTP_FIELD_ACCEPT_ENCODING 	"Accept-Encoding"
#define HTTP_VALUE_ACCEPT_ENCODING 	"gzip, deflate"
#define HTTP_FIELD_PRAGMA 			"Pragma"
#define HTTP_VALUE_PRAGMA 			"no-cache"
#define HTTP_FIELD_CONTENTTYPE	"Content-Type"
#define HTTP_VALUE_CONTENTTYPE	"application/octet-stream"   // "application/saip" 
#define HTTP_FIELD_CONNECTION		"Connection"
#define HTTP_VALUE_CONNECTION_KEEPALIVE	"Keep-Alive"
#define HTTP_VALUE_CONNECTION_CLOSED		"Closed"
#define HTTP_FIELD_PROXYCONNECTION	"Proxy-Connection"
#define HTTP_FIELD_CHARSET 		"Charset"
#define HTTP_VALUE_CHARSET 		"UTF-8"
#define HTTP_FIELD_SETCOOKIE			"Set-Cookie"
#define HTTP_FIELD_COOKIE				"Cookie"


#define HTTP_HEADER_APPEND	\
	HTTP_FIELD_UA, HTTP_VALUE_UA,\
	HTTP_FIELD_CONTENTTYPE, HTTP_VALUE_CONTENTTYPE,\
	HTTP_FIELD_ACCEPT, HTTP_VALUE_ACCEPT,\
	HTTP_FIELD_CHARSET, HTTP_VALUE_CHARSET,\
	HTTP_FIELD_CONNECTION, HTTP_VALUE_CONNECTION_KEEPALIVE,\
	HTTP_FIELD_PROXYCONNECTION, HTTP_VALUE_CONNECTION_KEEPALIVE
	
/**
 * \brief supported http method
 */
typedef enum HTTP_METHOD_E
{
	GET = 0, //"GET"
	POST//"POST"
}HTTPMETHOD;

/**
 * \brief http events
 */
typedef enum HTTP_EVENT_E
{
	/** sent when http socket connected */
	HTTPEVT_CONNECTED = SOCKEVT_CONNECTED,

	/** sent when http socket connect failed */
	HTTPEVT_CONNECTFAILED = SOCKEVT_CONNECTFAILED,

	/** sent when error happen */
	HTTPEVT_ERROR = SOCKEVT_ERROR,

	/** sent when socket closed */
	HTTPEVT_CLOSED = SOCKEVT_CLOSED,

	/** sent when get the http response header */
	HTTPEVT_RESPONSE_HEADER,

	/** sent when get the http response data */
	HTTPEVT_RESPONSE_DATA = SOCKEVT_RECVDATA,

	/** sent when one http response finished */
	HTTPEVT_RESPONSE_END
}HTTPEVENT;

typedef int32 (*FN_HTTPEVENT)(int32 userData, int32 evt, void* data);

/**
 * \brief Initialize the http module.
 *
 * For http module is dependent on socket module, so before initialize the http the 
 * socket module must be initialized.
 *
 * \sa Socket_Initialize
 */
VOID Http_Initialize(VOID);

/**
 * \brief Terminate the http module.
 *
 * When the http module is not needed by the application anymore, this function could
 * be called to release the http module.
 *
 * \sa Socket_Initialize
 */
VOID Http_Terminate(VOID);

/**
 * \brief Open a socket for http.
 *
 * \param ip the server ip address
 * \param port the server port number
 * \param fnEvent the http events handler
 * \return http socket handle on success, NULL otherwise
 */
PSOCKET Http_Open(Uint32 ip, Uint16 port, FN_HTTPEVENT fnEvent, Sint32 userData);

/**
 * \brief Close a http socket .
 * 
 * \param socket the socket handle
 * \param evt the close event
 * \return TRUE on success, FALSE otherwise
 */
BOOL Http_Close(PSOCKET socket, DWORD evt);

/**
 * \brief Format a http request header.
 *
 * This function is provide to format a request header for the default header can not used in a specific application.
 * The code look like this:
 * \code 
 *	Uint32 size = 0;
 *	pHeader = Http_FormatHeader(&size, GET, url
 *			"field1", "value1",
 *			"field2", "value2",
 *			"field3", "value3",
 *			NULL ); //do not forget the NULL ending
 * \endcode
 * The header will be "GET url HTTP1.1\r\nfield1:value1\r\nfield2:value2\r\nfield3:value3\r\n\r\n". After format
 * the header Http_Send can be called to send the request.
 *
 * \param[out] size the header size
 * \param method the http command
 * \param url the request url
 * \param ... the field/value pairs, and NULL ending
 * \return the formatted http header
 *
 * \sa Http_Send
 */
PCSTR Http_FormatHeader(Uint32* size, HTTPMETHOD method, PCSTR url, ... /* field/value and NULL ending*/);

/**
 * \brief Send the request through the http connection.
 *
 * This function can be used with Http_FormatHeader to write your own http method with specific header.
 *
 * \param socket the http socket handle
 * \param method the request method
 * \param buffer the http request buffer
 * \param size the send buffer size
 * \return TRUE on success, FALSE otherwise
 *
 * \sa Http_FormatHeader
 */
BOOL Http_Send(PSOCKET socket, PCSTR url, PBYTE buffer, Uint32 size);


/**
 * \brief Post the http data.
 *
 * \param socket the http socket
 * \param url the request url
 * \param buffer the post data
 * \param size post data size
 * \return TRUE on success, FALSE otherwise
 */
int32 Http_Post(PSOCKET socket, PCSTR host,uint16 port, PCSTR url, PBYTE buffer, Uint32 size);

/**
 * \brief Get the http response code.
 *
 * This can only be called after receive the EVENT HTTPEVT_RESPONSE_HEADER event.
 * otherwise undefined.
 *
 * \param socket the http socket handle
 * \return the response code
 */
Uint32 Http_GetResponseCode(PSOCKET socket);

/**
 * \brief Get the field value of the http header
 *
 * This can only be called after receive the EVENT HTTPEVT_RESPONSE_HEADER event.
 * otherwise undefined.
 *
 * \param socket the http socket handle
 * \param field the http header field
 * \return the value of the filed on success, NULL otherwise
 */
PCSTR Http_GetResponseField(PSOCKET socket, PCSTR field);

/** @} end of http */

#ifdef __cplusplus
}
#endif  /* __cplusplus */

#endif

